package com.example.front.arrange;

import com.alibaba.fastjson.JSON;
import com.github.rholder.retry.Retryer;
import com.github.rholder.retry.RetryerBuilder;
import com.github.rholder.retry.StopStrategies;
import com.github.rholder.retry.WaitStrategies;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * 编排支撑类
 *
 * @author haojianfen
 */
@Slf4j
@Component
public class TaskArrangeSupport {

    private static Map<Class<? extends AbstractRootTask>, List<Config>> arrangeConfigMap = new HashMap<>();

    public static List<Config> getArrangeConfigList(Class<? extends AbstractRootTask> contextClass) {
        return arrangeConfigMap.get(contextClass);
    }

    public static void setArrangeConfig(Map<Class<? extends AbstractRootTask>, List<Config>> configMap) {
        log.info("configMap:{}", JSON.toJSONString(configMap));
        arrangeConfigMap.putAll(configMap);
    }

    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 同步 运行编排任务
     *
     * @param threadPoolExecutor
     * @return 是否编排成功
     */
    public boolean runTaskSync(AbstractRootTask<?> rootTask, ThreadPoolExecutor threadPoolExecutor) {
        return runTask(rootTask, getArrangeConfigList(rootTask.getClass()), threadPoolExecutor, true);
    }
    /**
     * 异步运行编排任务
     *
     * @param threadPoolExecutor
     * @return 是否编排成功
     */
    public boolean runTaskAsync(AbstractRootTask<?> rootTask, ThreadPoolExecutor threadPoolExecutor) {
        return runTask(rootTask, getArrangeConfigList(rootTask.getClass()), threadPoolExecutor, false);
    }

    /**
     * 运行任务
     * @param rootTask
     * @param configList
     * @param threadPoolExecutor
     * @param isSync 是否同步运行任务
     * @return
     */
    private <T> boolean runTask(AbstractRootTask<T> rootTask, List<Config> configList, ThreadPoolExecutor threadPoolExecutor, boolean isSync) {
        if (null == rootTask || CollectionUtils.isEmpty(configList)) {
            return false;
        }
        this.buildTaskTree(rootTask, configList);
        CountDownLatch countDownLatch = new CountDownLatch(1);
        rootTask.startRun();
        handle(rootTask, countDownLatch, threadPoolExecutor);
        if (isSync) {
            try {
                //countDownLatch.await(1000, TimeUnit.MILLISECONDS);
                countDownLatch.await();
            } catch (InterruptedException e) {
                log.error("TaskSupport countDownLatch is error", e);
            }
        }
        return AbstractTask.isAllTaskSuccess(rootTask);
    }

    private <T> void handle(AbstractTask<T> task, CountDownLatch countDownLatch, ThreadPoolExecutor executor) {
        task.setFuture(executor.submit(() -> {
            T result = null;
            try {
                Retryer<T> build = RetryerBuilder.<T>newBuilder()
                        .retryIfException()
                        .withWaitStrategy(WaitStrategies.fixedWait(50, TimeUnit.MILLISECONDS))
                        .withStopStrategy(StopStrategies.stopAfterAttempt(3)).build();
                result = build.call(() -> {
                    T r = null;
                    if (TaskStatusEnum.SUCCESS.getStatus() != task.getStatus()) {
                        r = task.doHandle();
                    }
                    task.setStatus(TaskStatusEnum.SUCCESS.getStatus());
                    //log.info("Task:{}, thread:{}", task.getClass().getSimpleName(), Thread.currentThread().getName());
                    return r;
                });
            } catch (Exception e) {
                log.error("task is execute error,taskName:{}", Optional.of(task).map(AbstractTask::getName).orElse(null), e);
                task.setStatus(TaskStatusEnum.FAIL.getStatus());
            }
            if (CollectionUtils.isEmpty(task.getChildren())) {
                if (task.isAllTaskDone()) {
                    countDownLatch.countDown();
                }
            } else {
                for (AbstractTask<?> child : task.getChildren()) {
                    if (child.isReady() && child.startRun()) {
                        handle(child, countDownLatch, executor);
                    }
                }
            }
            return result;
        }));
    }

    /**
     * 构建任务树
     *
     * @param configList
     * @return
     */
    private AbstractRootTask buildTaskTree(AbstractRootTask rootTask, List<Config> configList) {
        if (CollectionUtils.isEmpty(configList)) {
            return null;
        }

        Map<Integer, AbstractTask<?>> subTaskMap = new HashMap<>();
        Config rootConfig = null;
        for (Config config : configList) {
            if (rootTask.getClass() == config.getTaskClass()) {
                rootConfig = config;
            } else {
                AbstractTask<?> abstractTask = (AbstractTask<?>) applicationContext.getBean(config.getTaskClass());
                abstractTask.setRootTask(rootTask);
                subTaskMap.put(config.getId(), abstractTask);
            }
        }
        Map<Integer, AbstractTask<?>> allTaskMap = new HashMap<>(subTaskMap);
        allTaskMap.put(rootConfig.getId(), rootTask);

        //构建头节点
        rootTask.setSubTaskList(allTaskMap.values());

        //构建子节点父亲节点
        for (Config item : configList) {
            if (rootTask.getClass() == item.getTaskClass()) {
                continue;
            }
            AbstractTask<?> task = subTaskMap.get(item.getId());
            List<AbstractTask<?>> parentAbstractTaskList = new ArrayList<>();
            List<Integer> parentIdList = item.getParentIdList();
            for (Integer parentId : parentIdList) {
                if (parentId.equals(rootConfig.getId())) {
                    parentAbstractTaskList.add(rootTask);
                } else {
                    parentAbstractTaskList.add(subTaskMap.get(parentId));
                }
            }
            task.setParents(parentAbstractTaskList);
        }

        //构建节点孩子节点
        List<Integer> configIdList = configList.stream().map(Config::getId).collect(Collectors.toList());
        for (Integer id : configIdList) {
            AbstractTask<?> task = allTaskMap.get(id);
            List<AbstractTask<?>> childrenList = new ArrayList<>();
            for (Config item : configList) {
                if (item.getParentIdList().contains(id)) {
                    AbstractTask<?> childTask = allTaskMap.get(item.getId());
                    childrenList.add(childTask);
                }
            }
            task.setChildren(childrenList);
        }
        return rootTask;
    }

}
